/**
 * 登录服务相关实现
 * ====================================================================================================================================
 * 登录的业务步骤大概可以分为以下步骤:
 * 1. 校验用户填写的表单
 * 2. 表单校验成功后, 根据接口错误码决定可用二次验证方式
 * 3. 用户点击获取验证码 -> 人机验证 -> 人机验证成功调用发送验证码接口 -> 发送验证码按钮倒计时(60s后可重发)
 * 4. 提交表单，再次调用登录接口
 * 4. 登录成功后需要上报当前用户登录的设备信息
 * 5. 请求用户信息和socketToken信息，并将登录接口data中access_token等信息一起整合成user存储
 * 
 * update: 登录/第三方绑定登录，都只在获取验证码时做人机校验，登录接口不再做人机校验；是否需要二次验证由登录接口第一次调用的错误码决定
 * ====================================================================================================================================
 */
import { Observable } from 'rxjs';
import { DomBridge } from 'src/common/services/dom.bridge';
import { injectable, inject, container } from 'src/common/services/di';
import { UserApiService, ymUserServiceFactory } from 'src/services/account/user';
import { signIn } from 'src/api/account';

type SupportLoginType = 'email' | 'phone_num';

interface ILoginForm {
  readonly type: SupportLoginType;
  username: string;
  values: any;
  rules: any;

  //设置的函数有参数和返回值的时候，用这种，没有得话，直接函数名：Funcion
  set(key: string, values: any): void;
}

class PhoneLoginForm extends DomBridge implements ILoginForm {
  readonly type = 'phone_num';
  public username = '';
  public countryCode = 'CN';
  public values: {
    areaCode: string | undefined;
    phoneNumber: string | undefined;
    password: string | undefined;
  } = {
    areaCode: '+86',
    phoneNumber: undefined,
    password: undefined,
  }

  public set(key: 'countryCode' | 'areaCode' | 'phoneNumber' | 'password', values: string | undefined): void {
    if(key === 'countryCode'){
      //@ts-ignore
      this.countryCode = values;
      return;
    }
    this.values[key] = values;
    if(key === 'phoneNumber' && this.values.areaCode){
      this.username = this.values.areaCode.replace('+', '00') + (values || '');
    }
    if(key === 'areaCode' && values && this.values.phoneNumber) {
      this.username = values.replace('+', '00') + (this.values.phoneNumber || '');
    }
  }

  get rules() {
    return {
      phone: [
        {name: 'isRequired', msg: '该字段不能为空'},
        {
          name: 'isPhone',
          msg: '手机号格式错误',
          // TODO 暂时不校验其他国家
          handler: (val: string) => {
            if (this.countryCode === 'CN') {
              return (/^1\d{10}$/.test(val));
            }
            if(!val) { return false; }
            return true;
          }
        },
      ],
      password: [
        { name: 'isRequired', msg: '该字段不能为空' },
      ]
    }
  }
}

export interface ILoginService {
  // flowStream$: Observable<any>;
  rules: any;
  accessCode: string;
  set: (key: string, value: string | undefined) => void;
  registerValidate(validate: () => boolean): void;
  doubleVerifySuccess: (params: any) => void;
  submit: () => void;
}

@injectable()
export class LoginFormService extends DomBridge implements ILoginService {
  private _params: any = null;
  private userService:UserApiService = ymUserServiceFactory();

  public accessCode: string = '';
  constructor(
    @inject('ILoginForm') private loginForm: ILoginForm,
    private workFlowService: any,
  ){
    super();
  }

  private login(checkResul?: any): void {
    const params = Object.assign({}, checkResul, this._params, this.accessCode ? {third_party: {access_code: this.accessCode}}: {});
    signIn(params).then(data => {
      //设置token之类的操作
      this.userService.updateProfile();
    }).catch(error => {
      //workflow工作流设置为登陆失败
    })
  }

  public set(key: string, value: string | undefined) {
    this.loginForm.set(key, value);
  }

  public submit(): void {
    //workflow设置为开始
    if(!this.validate()){
      //验证失败
      //设置workflow状态为fail
      return;
    }
    this._params = Object.assign({}, this.loginForm.values);

    if(!!this._params){
      this.login();
    }else {
      //workflow工作流设置为fail
    }
  }

  public doubleVerifySuccess(params: any): void {
    //工作流设置为开始
    this.login(params);
  }

  //这个workflow还没写出来，反正是把workflow的状态作为可检测对象返回出去
  get flowStream() {
    return this.workFlowService;
  }

  get rules() {
    return this.loginForm.rules;
  }
}

export const phoneLoginService = () => {
  container.register('ILoginForm', PhoneLoginForm);
  return container.resolve(LoginFormService);
}

